﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;

namespace simWaifu
{
    public static class SettingsHandler
    {
        //
        // stuff for the config/Settings.xml file
        //
        static private string aimlConfigFileName = "";
        static bool bEditableValues = true;
        static string startOfInternal = "START OF INTERNAL CONSTANTS";
        static string startOfEditable = "START OF EDITABLE CONSTANTS";
        static public List<string> internalBotConstantNames = new List<string>();
        static public List<string> internalBotConstantValues = new List<string>();
        static public List<string> editableBotConstantNames = new List<string>();
        static public List<string> editableBotConstantValues = new List<string>();

        // Load whole AIML config file
        static public void LoadAIMLConfigFile(string fileName)
        {
            // flush lists before loading data into them
            internalBotConstantNames.Clear();
            internalBotConstantValues.Clear();
            editableBotConstantNames.Clear();
            editableBotConstantValues.Clear();

            aimlConfigFileName = fileName;

            // Create an isntance of XmlTextReader and call Read method to read the file
            string testFile = Path.Combine(aimlConfigFileName);
            if (System.IO.File.Exists(testFile))
            {
                // first part of file is filled with constants which should not be changed by the user
                XmlTextReader textReader = new XmlTextReader(testFile);

                // Read until end of file
                while (textReader.Read())
                {
                    XmlNodeType nType = textReader.NodeType;
                    switch (nType)
                    {
                        // If node type us a declaration
                        case XmlNodeType.XmlDeclaration:
                            DebugMessageHandler.WriteMsgLine("Declaration:" + textReader.Value);
                            break;
                        // if node type is a comment
                        case XmlNodeType.Comment:
                            DebugMessageHandler.WriteMsgLine("Comment: " + textReader.Value);
                            if (textReader.Value.Equals(startOfInternal))
                            {
                                bEditableValues = false;
                                DebugMessageHandler.WriteMsgLine("########### Start of internal section ######");
                            }
                            if (textReader.Value.Equals(startOfEditable))
                            {
                                bEditableValues = true;
                                DebugMessageHandler.WriteMsgLine("########### Start of editable section ######");
                            }
                            break;
                        // if node type us an attribute
                        case XmlNodeType.Attribute:
                            DebugMessageHandler.WriteMsgLine("Attribute:" + textReader.Value);
                            break;
                        // if node type is an element
                        case XmlNodeType.Element:
                            // if element name is "item" we have a bot constant
                            if (textReader.Name.Equals("item"))
                            {
                                //OutputString("Element: <" + textReader.Name );
                                string botConstantName = "";
                                string botConstantValue = "";
                                int i = 0;
                                while (textReader.MoveToNextAttribute()) // Lesen der Attribute.
                                {
                                    //OutputString(" " + textReader.Name + "=\"" + textReader.Value + "\"");
                                    switch (i)
                                    {
                                        case 0: // name
                                            botConstantName = textReader.Value;
                                            break;
                                        case 1: // value
                                            botConstantValue = textReader.Value;
                                            break;
                                        default: // too many attributes
                                            DebugMessageHandler.WriteMsg("Too many attributes in item, only the first two will be used!");
                                            break;
                                    }
                                    i++;
                                }
                                //OutputLine(">");
                                DebugMessageHandler.WriteMsgLine(botConstantName + " = " + botConstantValue);
                                if (bEditableValues)
                                {
                                    editableBotConstantNames.Add(botConstantName);
                                    editableBotConstantValues.Add(botConstantValue);
                                }
                                else
                                {
                                    internalBotConstantNames.Add(botConstantName);
                                    internalBotConstantValues.Add(botConstantValue);
                                }
                            }
                            else if (!textReader.Name.Equals("root"))
                            {
                                DebugMessageHandler.WriteMsgLine("malformed Settings.xml file!!!");
                                DebugMessageHandler.WriteMsgLine("unknown item: " + textReader.Name);
                            }
                            break;
                        case XmlNodeType.Text: //Anzeigen des Textes in jedem Element.
                            DebugMessageHandler.WriteMsgLine("Text: " + textReader.Value);
                            break;
                        case XmlNodeType.EndElement: //Anzeigen des Endes des Elements.
                            DebugMessageHandler.WriteMsgLine("Element: </" + textReader.Name + ">");
                            break;
                        // if node type is an entity\
                        case XmlNodeType.Entity:
                            DebugMessageHandler.WriteMsgLine("Entity:" + textReader.Value);
                            break;
                        // if node type is a Process Instruction
                        case XmlNodeType.ProcessingInstruction:
                            DebugMessageHandler.WriteMsgLine("ProcessingInstruction:" + textReader.Value);
                            break;
                        // if node type a document
                        case XmlNodeType.DocumentType:
                            DebugMessageHandler.WriteMsgLine("Document:" + textReader.Value);
                            break;
                        // if node type is white space
                        case XmlNodeType.Whitespace:
                            //OutputLine("WhiteSpace:" + textReader.Value);
                            break;
                        // unhandled node type if node type is white space
                        default:
                            DebugMessageHandler.WriteMsgLine("Unknown node type.");
                            break;
                    }
                }
                textReader.Close();
            }
            else
            {
                DebugMessageHandler.WriteMsgLine("Settings.xml file not found!");
            }
        }

        // write bot constant: <item name="itemName" value="itemValue">
        static private void WriteXML_BotSetting(XmlTextWriter writer, string itemName, string itemValue)
        {
            writer.WriteStartElement("item", null);
            writer.WriteAttributeString("name", itemName);
            writer.WriteAttributeString("value", itemValue);
            writer.WriteEndElement();
        }

        // write the whole AIML settings file
        static public void SaveAIMLConfigFile()
        {
            // xml writer used by multiple functions
            XmlTextWriter writer = null;

            // Encoding type. (original files are UTF-8)
            // todo: maybe change to unicode, but that will be hard 
            // since the chatbot strips everything down to latin A-Z0-9
            System.Text.Encoding encType = System.Text.Encoding.UTF8;
            writer = new XmlTextWriter(aimlConfigFileName, encType);
            writer.Formatting = Formatting.Indented;

            writer.WriteStartDocument();

            writer.WriteComment("Settings for the simWaifu chat function.");
            writer.WriteComment("Please do not edit manually unless you know what you are doing. ");
            writer.WriteComment("You can edit these settings in the menu (ChatSettings).");

            writer.WriteStartElement("root"); // <root>

            //
            // write non editable settings
            //
            writer.WriteComment("Internal settings which SHOULD NOT be changed by the user");
            writer.WriteComment(startOfInternal);
            for (int i = 0; i < internalBotConstantNames.Count; i++)
            {
                WriteXML_BotSetting(writer, internalBotConstantNames[i].ToString(),
                    internalBotConstantValues[i].ToString());
            }

            //
            // write editable settings
            //
            writer.WriteComment("waifu/husbando specific settings which can be changed by the user");
            writer.WriteComment(startOfEditable);
            for (int e = 0; e < editableBotConstantNames.Count; e++)
            {
                WriteXML_BotSetting(writer, editableBotConstantNames[e].ToString(),
                    editableBotConstantValues[e].ToString());
            }

            writer.WriteEndElement(); // </root>

            writer.Flush();
            writer.Close();
            writer = null;
        }

    } // end class SettingsHandler
} // end namespace simWaifu
